package com.github.xtranslation.core.threadpool;


import io.vavr.control.Option;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Optional;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

/**
 * CommonExecutor:线程池工具类
 *
 * @author zhangxiaoxiang
 * @since 2023/9/2
 */
public class DefaultExecutor {

    private static final Logger log = LoggerFactory.getLogger(DefaultExecutor.class);

    private static final AtomicReference<XTranslationThreadPoolManager> THREAD_POOL_MANAGER = new AtomicReference<>();

    private static final ThreadPoolExecutor DEFAULT_EXECUTOR;

    static {
        log.debug("init com.github.xtranslation.core.threadpool.CommonExecutor");
        int processors = Runtime.getRuntime().availableProcessors();
        DEFAULT_EXECUTOR = new ThreadPoolExecutor(
                processors,
                2 * processors,
                30L, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(1000),
                new MyThreadFactory("x-translation", "common"),
                (r, exe) -> {
                    throw new RejectedExecutionException("Network busy, please try again later");
                }
        );
    }

    private DefaultExecutor() {
    }

    /**
     * 设置自定义线程池管理器
     * <p>
     * 使用方可以通过此方法注册自己的线程池实现，框架将使用该实现替代默认线程池。
     * 注意：此方法应该在应用启动初期调用，避免线程池已经在使用后再替换。
     * </p>
     *
     * @param threadPoolManager 自定义线程池管理器
     */
    public static void setThreadPoolManager(XTranslationThreadPoolManager threadPoolManager) {

        THREAD_POOL_MANAGER.set(threadPoolManager);
    }

    /**
     * 获取线程池执行器
     * <p>
     * 如果使用方设置了自定义线程池管理器，则返回自定义实现；
     * 否则返回默认线程池实现。
     * </p>
     *
     * @return 线程池执行器实例
     */
    public static ThreadPoolExecutor getExecutor() {
        return io.vavr.control.Try.of(() -> {
                    ThreadPoolExecutor executor = Optional.ofNullable(THREAD_POOL_MANAGER.get())
                            .map(XTranslationThreadPoolManager::getExecutor)
                            .orElse(DEFAULT_EXECUTOR);

                    // 打印当前使用的线程池配置参数
                    log.info("Current thread pool configuration parameters: corePoolSize={}, maximumPoolSize={}, keepAliveTime={}s, queueCapacity={}",
                            executor.getCorePoolSize(),
                            executor.getMaximumPoolSize(),
                            executor.getKeepAliveTime(TimeUnit.SECONDS),
                            executor.getQueue().remainingCapacity());

                    return executor;
                }).onFailure(throwable -> log.error("Failed to get thread pool executor", throwable))
                .get();
    }

    /**
     * 销毁线程池
     * <p>
     * 销毁自定义线程池（如果存在）或默认线程池
     * </p>
     */
    public static void destroy() {
        Option.of(THREAD_POOL_MANAGER.get())
                .peek(XTranslationThreadPoolManager::destroy)
                .onEmpty(() -> Option.of(DEFAULT_EXECUTOR)
                        .filter(executor -> !executor.isShutdown())
                        .forEach(ThreadPoolExecutor::shutdown));
    }
}
